home *** CD-ROM | disk | FTP | other *** search
- Subject: list-of-numbers generator
- Newsgroups: mod.sources
- Approved: jpn@panda.UUCP
-
- Mod.sources: Volume 4, Issue 53
- Submitted by: hplabs!hpfcla!ajs (Alan Silverstein)
-
- Greetings. Here's an almost-ultimate (?) implementation of a list-of-numbers
- generator. It's carefully coded, proof-read, tested, and documented. Of
- course I've only run it on local systems (HP9000s), so I can't guarantee
- ultimate portability.
-
- [
- It uses the new system V random number generator functions - srand48 and
- lrand48. You should be able to replace srand48() with srand, and lrand48
- with rand() to make this run on most other systems.
- - John Nelson, Moderator
- ]
-
- Alan Silverstein, Hewlett-Packard Fort Collins Systems Division, Colorado
- {ihnp4 | hplabs}!hpfcla!ajs, 303-226-3800 x3053, N 40 31'31" W 105 00'43"
-
-
- #! /bin/sh
- # This is a shell archive, meaning:
- # 1. Remove everything above the #! /bin/sh line.
- # 2. Save the resulting text in a file.
- # 3. Execute the file with /bin/sh (not csh) to create the files:
- # nums.1
- # nums.c
- # This archive created: Mon Apr 7 11:47:53 1986
- export PATH; PATH=/bin:$PATH
- echo shar: extracting "'nums.1'" '(2704 characters)'
- if test -f 'nums.1'
- then
- echo shar: will not over-write existing file "'nums.1'"
- else
- cat << \SHAR_EOF > 'nums.1'
- .TH NUMS 1 "HP Experimental"
- .ad b
- .SH NAME
- nums \- print a list of numbers
- .SH SYNOPSIS
- .B nums
- [
- .B \-lr
- ] [
- .BI \-s \0size
- ] [
- .BI \-w \0width
- ]
- .I value
- [
- .I value2
- ]
- .SH DESCRIPTION
- This command prints to standard output all integer values from 1 to
- .IR value ,
- or if you give two numbers, from
- .I value
- to
- .IR value2 ,
- one number per output line.
- If
- .I value
- alone is less than 1, or
- .I value2
- is less than
- .IR value ,
- it steps backwards rather than forwards.
- .PP
- This command may be useful with "for" loops in shell scripts
- (see example below)
- or for generating column headers or row numbers
- before adding text in an editor.
- .PP
- Options are:
- .TP
- .B \-l
- Print all output numbers on a single line,
- i.e. follow each except the last with a blank instead of a newline.
- .TP
- .B \-r
- Print the numbers in random order.
- A random number generator is seeded to the time plus
- process number plus real userid plus real groupid.
- Then successive random values are used to index into an array with one
- entry for each output value.
- When the index is of a value already printed,
- the program searches backward (with wrap-around)
- for the previous not-yet-printed number,
- so it terminates in a predictable time.
- .TP
- .BI \-s \0size
- Set the step size (increment) to a non-zero integer (default = 1).
- Starting with the first value,
- the program steps either forwards or backwards by the given
- .IR size ,
- as appropriate, until it passes the second value.
- The sign of
- .I size
- is irrelevant;
- the direction is determined by the given value(s).
- .TP
- .BI \-w \0width
- Right-justify output numbers in fields of at least the given width (columns)
- by padding with leading blanks as necessary.
- If
- .I width
- is negative, numbers are left-justified.
- .PP
- Separate options from
- .I value
- with "\fB--\fR" if
- .I value
- is negative.
- .SH EXAMPLES
- .TP
- num 5
- Print five lines containing the numbers 1, 2, 3, 4, and 5.
- .TP
- num \-l \-w4 \-\- -1 3
- Print the numbers -1, 0, 1, 2, and 3 on a single line,
- each in a field four columns wide (plus leading blank separators), e.g.:
- .nf
- .RS
-
- \0\0-1 \0\0\00 \0\0\01 \0\0\02 \0\0\03
- .RE
- .fi
- .TP
- num \-rs10 42
- Print the numbers 1, 11, 21, 31, and 41 in random order.
- .PP
- .nf
-
- for n in `num 20 5`
- do
- whatever
- done
- .PD 0
- .IP ""
- Do "whatever" 16 times, with "n" set to 20, 19, ..., 5.
- .PD
- .SH SEE ALSO
- xargs(1), time(2), getpid(2), getuid(2), getgid(2), drand48(3c)
- .SH DIAGNOSTICS
- Prints a message to standard error and exits non-zero if
- invoked wrong or it can't calloc() needed memory for the
- .B \-r
- option.
- .SH LIMITATIONS
- It doesn't understand real numbers.
- .PP
- If the number of numbers printed is not an integer divisor of the range of
- the random number generator,
- the output is not "precisely" random.
- SHAR_EOF
- if test 2704 -ne "`wc -c < 'nums.1'`"
- then
- echo shar: error transmitting "'nums.1'" '(should have been 2704 characters)'
- fi
- fi
- echo shar: extracting "'nums.c'" '(4958 characters)'
- if test -f 'nums.c'
- then
- echo shar: will not over-write existing file "'nums.c'"
- else
- cat << \SHAR_EOF > 'nums.c'
- /*
- * Print a list of numbers.
- * See the manual entry for details.
- */
-
- #include <stdio.h>
-
-
- /*********************************************************************
- * MISCELLANEOUS GLOBAL VALUES:
- */
-
- #define PROC /* null; easy to find procs */
- #define FALSE 0
- #define TRUE 1
- #define CHNULL ('\0')
- #define CPNULL ((char *) NULL)
- #define REG register
-
- char *usage[] = {
- "usage: %s [-lr] [-s size] [-w width] value [value2]",
- "-l print all one one line (default: one number per line)",
- "-r print numbers in random order",
- "-s set step size (increment, default = 1)",
- "-w print numbers in fields of given width (default: no padding)",
- "Prints numbers from 1 to value, or value to value2",
- CPNULL,
- };
-
- char *myname; /* how program was invoked */
-
- int lflag = FALSE; /* -l (all one line) option */
- int rflag = FALSE; /* -r (randomize) option */
-
- int step = 1; /* value from -s option */
- int width = 0; /* value from -w option */
-
-
- /************************************************************************
- * M A I N
- */
-
- PROC main (argc, argv)
- int argc;
- char **argv;
- {
- extern int optind; /* from getopt() */
- extern char *optarg; /* from getopt() */
- REG int option; /* option "letter" */
- REG int value1 = 1; /* first value */
- REG int value2; /* second value */
- char format [20]; /* for printing numbers */
- REG char sep; /* leading separator */
-
- /*
- * PARSE ARGUMENTS:
- */
-
- myname = *argv;
-
- while ((option = getopt (argc, argv, "lrs:w:")) != EOF)
- {
- switch (option)
- {
- case 'l': lflag = TRUE; break;
- case 'r': rflag = TRUE; break;
-
- case 's': step = atoi (optarg); break;
- case 'w': width = atoi (optarg); break;
-
- default: Usage();
- }
- }
-
- argc -= optind; /* skip options */
- argv += optind;
-
- /*
- * MORE ARGUMENT CHECKS:
- */
-
- if (argc == 1)
- {
- value2 = atoi (argv [0]);
- }
- else if (argc == 2)
- {
- value1 = atoi (argv [0]);
- value2 = atoi (argv [1]);
- }
- else
- {
- Usage();
- }
-
- if (step == 0)
- Error ("step size cannot be zero");
-
- /*
- * FINISH INITIALIZING:
- */
-
- if (((step < 0) && (value1 < value2))
- || ((step > 0) && (value1 > value2))) /* harmless if values equal */
- {
- step = -step; /* invert */
- }
-
- sprintf (format, (width ? "%%%dd" : "%%d"), width);
- sep = lflag ? ' ' : '\n';
-
- /*
- * PRINT NUMBERS:
- */
-
- if (rflag)
- PrintRandom (value1, value2, format, sep);
- else
- {
- REG int forward = (step > 0);
-
- printf (format, value1);
-
- while (forward ? ((value1 += step) <= value2)
- : ((value1 += step) >= value2))
- {
- putchar (sep);
- printf (format, value1);
- }
- }
-
- putchar ('\n'); /* finish last line */
- exit (0);
-
- } /* main */
-
-
- /************************************************************************
- * P R I N T R A N D O M
- *
- * Given value limits, print format, leading separator, and global step size
- * (positive or negative matching value limits), print numbers in random
- * order. Don't print the trailing newline for the last line.
- */
-
- PROC PrintRandom (value1, value2, format, sep)
- REG int value1; /* base limit */
- int value2; /* end limit */
- REG char *format; /* how to print */
- REG char sep; /* leading char */
- {
- REG int remain = (value2 - value1) / step;
- REG int count = remain + 1; /* total to print */
- REG int *done; /* this number printed? */
- REG int which; /* index in done[] */
-
- /*
- * INITIALIZE:
- */
-
- if ((done = (int *) calloc (count, sizeof (int))) == (int *) NULL)
- Error ("calloc %d integers failed", count);
-
- srand48 (time ((int *) 0) + getpid() + getuid() + getgid());
-
- done [which = (lrand48() % count)] = TRUE;
- printf (format, value1 + (which * step)); /* first one */
-
- /*
- * PRINT RANDOM NUMBERS:
- */
-
- while (remain-- > 0) /* more to do */
- {
- which = lrand48() % count; /* not *precisely* random */
-
- while (done [which]) /* already taken */
- {
- if (--which < 0) /* wrap around */
- which = count - 1;
- }
-
- done [which] = TRUE;
- putchar (sep);
- printf (format, value1 + (which * step));
- }
-
- } /* PrintRandom */
-
-
- /************************************************************************
- * U S A G E
- *
- * Print usage messages (char *usage[]) to stderr and exit nonzero.
- * Each message is followed by a newline.
- */
-
- PROC Usage()
- {
- REG int which = 0; /* current line */
-
- while (usage [which] != CPNULL)
- {
- fprintf (stderr, usage [which++], myname);
- putc ('\n', stderr);
- }
-
- exit (1);
-
- } /* Usage */
-
-
- /************************************************************************
- * E R R O R
- *
- * Print an error message to stderr and exit nonzero. Message is preceded
- * by "<myname>: " using global char *myname, and followed by a newline.
- */
-
- /* VARARGS */
- PROC Error (message, arg1, arg2, arg3, arg4)
- char *message;
- long arg1, arg2, arg3, arg4;
- {
- fprintf (stderr, "%s: ", myname);
- fprintf (stderr, message, arg1, arg2, arg3, arg4);
- putc ('\n', stderr);
-
- exit (1);
-
- } /* Error */
- SHAR_EOF
- if test 4958 -ne "`wc -c < 'nums.c'`"
- then
- echo shar: error transmitting "'nums.c'" '(should have been 4958 characters)'
- fi
- fi
- exit 0
- # End of shell archive
-